using System.Collections;
using System.Collections.Generic;
using cuberga.Utils;

namespace cuberga.GA.Permutation
{
    public class HalfOX
    {
        private Tour _tourFather;
        private Tour _tourMother;
        private Tour _tourChild;
        private int _iLeftCutPoint;
        private int _iRightCutPoint;
        private Queue<int> _queueCities;

        public HalfOX(Genotype tourFather, Genotype tourMother, int iLeftCutPoint, int iRightCutPoint)
        {
            _tourFather = new Tour( (int[])tourFather.ToStructure());
            _tourMother = new Tour( (int[])tourMother.ToStructure()); ;
            _iLeftCutPoint = iLeftCutPoint;
            _iRightCutPoint = iRightCutPoint;
        }

        public PermutationGenotype GetOffspring()
        {
            InitChildWithNaN();
            InitCitiesList();
            CopyMappedCities();
            CopyUnmappedCities();

            PermutationGenotype genotype = new PermutationGenotype( _tourChild.ToArray());
            return genotype;
        }

        private void InitChildWithNaN()
        {
            ArrayList arrayOfNaN = ArrayList.Repeat(-1, _tourFather.Length);
            _tourChild = new Tour(arrayOfNaN);
        }

        private void InitCitiesList()
        {
            Tour tourOrderedCities = _tourMother.SubtourFromIndex(_iRightCutPoint);
            tourOrderedCities.AddTour(_tourMother.Subtour(0, _iRightCutPoint));

            _queueCities = new Queue<int>();
            for (int i = 0; i < tourOrderedCities.Length; i++)
            {
                int iCity = tourOrderedCities[i];
                if (!IsCityInMappedChapter(iCity))
                    _queueCities.Enqueue(iCity);
            }
        }

        private bool IsCityInMappedChapter(int iCity)
        {
            Tour tourMappingChapter =
                _tourFather.Subtour(_iLeftCutPoint, _iRightCutPoint - _iLeftCutPoint);
            if (tourMappingChapter.IndexOfCity(iCity) == -1)
                return false;
            else
                return true;
        }

        private void CopyMappedCities()
        {
            for (int i = _iLeftCutPoint; i < _iRightCutPoint; i++)
            {
                _tourChild[i] = _tourFather[i];
            }
        }

        private void CopyUnmappedCities()
        {
            CopyUnmappedCities(_iRightCutPoint, _tourChild.Length);
            CopyUnmappedCities(0, _iLeftCutPoint);
        }

        private void CopyUnmappedCities(int iLeftBound, int iRightBound)
        {
            for (int i = iLeftBound; i < iRightBound; i++)
            {
                int iCityToInsert = GetNextCity();
                _tourChild[i] = iCityToInsert;
            }
        }

        private int GetNextCity()
        {
            return _queueCities.Dequeue();
        }
    }
}
